#pragma once

#include <cstddef>
#include <stdint.h>

#include <string>
#include <vector>

namespace hawking {
namespace indexlib {

class AttributeFieldList {
public:
    static constexpr std::string_view empty_sv{};

    AttributeFieldList() = default;
    ~AttributeFieldList() = default;

    class Iterator {
    public:
        Iterator(const std::vector<std::string_view>& field_list) :
            field_list_(field_list), cursor_(field_list.cbegin()) {}
        ~Iterator() = default;

        bool HasNext() const {
            return cursor_ != field_list_.cend();
        }

        const std::string_view& Next(int32_t* field_id) {
            if (cursor_ != field_list_.cend()) {
                const std::string_view& value = *cursor_;
                *field_id = field_id_;
                ++cursor_;
                ++field_id_;
                MoveToNext_();
                return value;
            }

            return empty_sv;
        }

        const std::string_view& Next() {
            if (cursor_ != field_list_.cend()) {
                const std::string_view& value = *cursor_;
                ++cursor_;
                ++field_id_;
                MoveToNext_();
                return value;
            }

            return empty_sv;
        }

    private:
        void MoveToNext_() {
            if (cursor_ != field_list_.cend() && cursor_->empty()) {
                ++cursor_;
                ++field_id_;
            }
        }

        const std::vector<std::string_view>& field_list_;
        std::vector<std::string_view>::const_iterator cursor_;
        int32_t field_id_ = 0;
    };

    void Reserve(size_t size) {
        field_vector_.resize(size);
    }

    void Reset() {
        field_vector_.clear();
    }

    Iterator CreateIterator() const {
        return Iterator(field_vector_);
    }

    bool SetField(int32_t field_id, const std::string_view& value) {
        if (field_id >= field_vector_.size() || value.empty()) {
            return false;
        }

        field_vector_[field_id] = value;
        return true;
    }

    const std::string_view& GetField(int32_t field_id) const {
        return (field_id >= field_vector_.size()) ? empty_sv : field_vector_[field_id];
    }

    bool HasField(int32_t field_id) const {
        return field_id < field_vector_.size();
    }

private:
    std::vector<std::string_view> field_vector_;
};

class AttributeDocument {
public:
    AttributeDocument() = default;
    ~AttributeDocument() = default;

    AttributeFieldList::Iterator CreateIterator() const {
        return field_list_.CreateIterator();
    }

    bool SetField(int32_t field_id, const std::string_view& value) {
        return field_list_.SetField(field_id, value);
    }

    const std::string_view& GetField(int32_t field_id) const {
        return field_list_.GetField(field_id);
    }

    bool HasField(int32_t field_id) const {
        return field_list_.HasField(field_id);
    }

    void Reserve(size_t size) {
        field_list_.Reserve(size);
    }

private:
    AttributeFieldList field_list_;
};

}
}